/*
#Copyright (c) 2013, Philippe Bordron <philippe.bordron@gmail.com>
#
# This file is part of SIPPER.
#
# DCC is free software: you can redistribute it and/or modify
# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# DCC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU LESSER GENERAL PUBLIC LICENSE for more details.
#
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
# along with SIPPER.  If not, see <http://www.gnu.org/licenses/>
*/
package combi.wip.sipper.modeling.integratedModel.graphs;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;

import combi.utils.Pair;
import combi.wip.sipper.modeling.Protein;
import combi.wip.sipper.modeling.genomes.Gene;
import combi.wip.sipper.modeling.integratedModel.GenomicModel;
import combi.wip.sipper.modeling.reactions.Reaction;



public class GraphGenomicModel<G extends Gene<E>, C, R extends Reaction<C>, E extends Protein> {

	protected GenomicModel<G, C, R, E> model;
	protected DefaultDirectedWeightedGraph<Integer, DefaultWeightedEdge> graphModel;
	protected List<Pair<String>> labels;
	protected List<String> rLabels;
	protected List<String> gLabels;
	protected Map<Pair<String>, Integer> vertices;

	public GraphGenomicModel(GenomicModel<G, C, R, E> model)
	{
		this.model = model;
		this.labels = new ArrayList<Pair<String>>();
		this.gLabels = new ArrayList<String>();
		this.rLabels = new ArrayList<String>();
		this.vertices = new HashMap<Pair<String>, Integer>();
	}

	public GraphGenomicModel(GenomicModel<G, C, R, E> model, DefaultDirectedWeightedGraph<Integer, DefaultWeightedEdge> graphModel, List<Pair<String>> labels, List<String> rLabels,  List<String> gLabels, Map<Pair<String>, Integer> vertices)
	{
		this.model = model;
		this.graphModel = graphModel;
		this.labels = labels;
		this.gLabels = gLabels;
		this.rLabels = rLabels;
		this.vertices = vertices;
	}
	
	public GraphGenomicModel(GraphGenomicModel<G, C, R, E> other)
	{
		this.model= other.model;
		this.labels = new ArrayList<Pair<String>>(other.labels);
		this.gLabels = new ArrayList<String>(other.gLabels);
		this.rLabels = new ArrayList<String>(other.rLabels);
		this.vertices = new HashMap<Pair<String>, Integer>(other.vertices);
		this.generateGraph();
	}
	
	public void generateGraph() {
		graphModel = new DefaultDirectedWeightedGraph<Integer, DefaultWeightedEdge>(DefaultWeightedEdge.class);
		int v = 0;
		for(Reaction<C> r : model.getMetabolism().getReactionSet())
		{
			for (Gene<E> g : model.getGenes(r))
			{
				Pair<String> l = new Pair<String>(g.getId(), r.getId());
				if (!vertices.containsKey(l))
				{
					labels.add(l);
					gLabels.add(l.getFirst());
					rLabels.add(l.getSecond());
					graphModel.addVertex(v);
					vertices.put(l, v);
					v++;
				}
			}

		}
		//System.err.println(graphModel.vertexSet());
		for(Reaction<C> rSrc : model.getMetabolism().getReactionSet())
		{
			for(Reaction<C> rDest : model.getMetabolism().nextReactions(rSrc))
			{
				for (Gene<E> gSrc : model.getGenes(rSrc))
				{
					for (Gene<E> gDest : model.getGenes(rDest))
					{
						int src = vertices.get(new Pair<String>(gSrc.getId(), rSrc.getId()));
						int	dest = vertices.get(new Pair<String>(gDest.getId(), rDest.getId()));
						//System.err.println(src + "->" + dest);
						DefaultWeightedEdge e = graphModel.addEdge(src, dest);
						graphModel.setEdgeWeight(e, model.getDistance((G)gSrc, (G)gDest));
					}
				}
			}
		}
	}

	public DefaultDirectedWeightedGraph<Integer, DefaultWeightedEdge> getGraph()
	{
		return this.graphModel;
	}
	
	public Pair<String> getLabel(int vertex)
	{
		return labels.get(vertex);
	}

	
	public String getRLabel(int vertex)
	{
		return rLabels.get(vertex);
	}

	
	public String getGLabel(int vertex)
	{
		return gLabels.get(vertex);
	}

}
